﻿#-------------------------------------------------------------------------------
# Name:        pyissue
# Purpose:
#
# Author:      Sergey Pikhovkin (s@pikhovkin.ru)
#
# Created:     15.02.2011
# Copyright:   (c) AlteGroup 2011
# Licence:     <AlteGroup>
#-------------------------------------------------------------------------------
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from __future__ import with_statement
#from sqlite3 import dbapi2 as sqlite3
import psycopg2
from contextlib import closing
import time
from hashlib import md5
from datetime import datetime
from functools import wraps
import mimetypes

from flask import Flask, request, session, url_for, redirect, \
     render_template, abort, g, flash
from werkzeug import check_password_hash, generate_password_hash


# configuration
DEBUG = True
SECRET_KEY = 'a ™бb_~С“‰DќЛЮ{*©b„ZTх­C'
DATABASE = 'pyissue.db'

USERNAME = 'admin'
PASSWORD = '123'

db_settings = dict(
    host='pg-utf.sweb.ru',
    database='artsunorg',
    user='artsunorg',
    password='Rheptyinthy359'
)

# create our little application :)
app = Flask(__name__)
app.config.from_object(__name__)
app.config.from_envvar('PYISSUE_SETTINGS', silent=True)

def login_required(redirect_to='login'):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            if g.user is None:
                return redirect(url_for(redirect_to)) #, next=request.url))
            return f(*args, **kwargs)
        return wrapper
    return decorator

def templated(template=None):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            template_name = template
            if template_name is None:
                template_name = request.endpoint.replace('.', '/') + '.html'
            ctx = f(*args, **kwargs)
            if ctx is None:
                ctx = {}
            elif not isinstance(ctx, dict):
                return ctx
            return render_template(template_name, **ctx)
        return wrapper
    return decorator

def connect_db():
    """Returns a new connection to the database."""
    #return sqlite3.connect(app.config['DATABASE'])
    return psycopg2.connect(**db_settings)

def init_db():
    """Creates the database tables."""
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql') as f:
            db.cursor().executescript(f.read())
        db.commit()
'''
def query_db(query, args=(), one=False):
    """Queries the database and returns a list of dictionaries."""
    cur = g.db.cursor()
    cur.execute(query, args)
    rv = [dict((cur.description[idx][0], value)
               for idx, value in enumerate(row)) for row in cur.fetchall()]
    return (rv[0] if rv else None) if one else rv
'''
def query_db(query, args=(), one=False):
    """Queries the database and returns a list of dictionaries."""
    cur = g.db.cursor()
    cur.execute(query, args)
    rv = list()
    d = dict()
    for row in cur.fetchall():
        d.clear()
        for idx, value in enumerate(row):
            if isinstance(value, (str, unicode)):
                value = value.decode('utf-8')
            d[cur.description[idx][0]] = value
        if d:
            rv.append(dict(**d))

    return (rv[0] if rv else None) if one else rv

def get_user_id(username):
    """Convenience method to look up the id for a username."""
    cur = g.db.cursor()
    cur.execute('select "id" from "user" where "login" = %s',
                       (username,))
    rv = cur.fetchone()
    cur.close()
    return rv[0] if rv else None

def format_datetime(timestamp):
    """Format a timestamp for display."""
    return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d @ %H:%M')

@app.before_request
def before_request():
    """Make sure we are connected to the database each request and look
    up the current user so that we know he's there.
    """
    g.db = connect_db()
    g.user = None
    if 'user_id' in session:
        g.user = query_db('select "id", "login", "password" from "user" where "id" = %s',
                          (session['user_id'],), one=True)

@app.after_request
def after_request(response):
    """Closes the database again at the end of the request."""
    g.db.close()
    return response

@app.route('/')
@login_required('login')
def index():
    if g.user:
        return redirect(url_for('projects'))

@app.route('/login/', methods=['GET', 'POST'])
@templated('login.html')
def login():
    if g.user:
        return redirect(url_for('index'))

    error = None
    if request.method == 'POST':
        user = query_db('select "id", "password" from "user" where "login" = %s',
            (request.form['username'],), one=True)
        if user is None:
            error = 'Invalid username'
        elif not check_password_hash(user['password'],
                                     request.form['password']):
            error = 'Invalid password'
        else:
            flash('You were logged in')
            session['user_id'] = user['id']
            return redirect(url_for('index'))
    return dict(error=error)

@app.route('/register/', methods=['GET', 'POST'])
@templated('register.html')
def register():
    """Registers the user."""
    if g.user:
        return redirect(url_for('index'))

    error = None
    if request.method == 'POST':
        if not request.form['username']:
            error = 'You have to enter a username'
            '''
            elif not request.form['email'] or \
                     '@' not in request.form['email']:
                error = 'You have to enter a valid email address'
            '''
        elif not request.form['password']:
            error = 'You have to enter a password'
            '''
            elif request.form['password'] != request.form['password2']:
                error = 'The two passwords do not match'
            '''
        elif get_user_id(request.form['username']) is not None:
            error = 'The username is already taken'
        else:
            cur = g.db.cursor()
            cur.execute('insert into "user"("login", "password") values (%s, %s)',
                (request.form['username'],
                    generate_password_hash(request.form['password']),))
            g.db.commit()
            cur.close()
            flash('You were successfully registered and can login now')
            return redirect(url_for('login'))
    return dict(error=error)

@app.route('/projects/')
@templated('projects.html')
@login_required('login')
def projects():
    error = None
    projects = query_db('select "id", "title" from "project" where "user_id"=%s order by "title"',
        (g.user['id'],))
    if not projects:
        error = 'Empty list projects'
    return dict(projects=projects, error=error)

def is_project(id):
    project = query_db('select "id" from "project" where "user_id"=%s and "id"=%s',
        (g.user['id'], id,), one=True)
    return not project is None

def is_issue(pid, id):
    issue = None
    if is_project(pid):
        issue = query_db('select "id" from "issue" where "project_id"=%s and "id"=%s',
            (pid, id,), one=True)
    return not issue is None

@app.route('/projects/<int:id>/')
@templated('issues.html')
@login_required('login')
def project_id(id):
    if not is_project(id):
        return redirect(url_for('index'))
    session['project_id'] = id
    issues = query_db('select "issue"."id" as "id", "issue"."title" as "title", "state"."title" as "state" from "issue", "state", "project" where "issue"."project_id"="project"."id" and "issue"."project_id"=%s and "state"."id"="issue"."state_id" order by "issue"."title"',
        (id,))
    error = ''
    if not issues:
        error = 'Empty list issues'
    return dict(issues=issues, error=error)

@app.route('/issues/<int:id>/')
@templated('issue_item.html')
@login_required('login')
def issue_id(id):
    pid = session['project_id']
    if not is_issue(pid, id):
        return redirect(url_for('project_id', id=pid))
    session['issue_id'] = id
    issue = query_db('select "issue"."id" as "id", "issue"."title" as "title", "issue"."description" as "description", "state"."title" as "state" from "issue", "state" where "issue"."id"=%s and "state"."id"="issue"."state_id"',
        (id,), one=True)
    return dict(issue=issue, error=None)

@app.route('/logout/')
def logout():
    """Logs the user out."""
    flash('You were logged out')
    session.pop('user_id', None)
    session.pop('project_id', None)
    session.pop('issue_id', None)
    return redirect(url_for('index'))

@app.route('/add_issue/', methods=['GET', 'POST'])
@templated('add_issue.html')
@login_required('login')
def add_issue():
    if request.method == 'GET':
        states = query_db('select "id", "title", "selected" from "state" order by "title"')
        return dict(states=states)
    if request.method == 'POST':
        if request.form['title']:
            project_id = session['project_id']
            state_id = int(request.form['state'])

            cur = g.db.cursor()
            cur.execute('insert into "issue"("project_id", "state_id", "title", "description") values(%s, %s, %s, %s)',
                (project_id, state_id, request.form['title'], request.form['description'],))
            g.db.commit()
            cur.close()
            flash('Your issue was added')
        return redirect(url_for('project_id', id=project_id))

if __name__ == '__main__':
    app.run(debug=True)